package com.un.ebs.memorial.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.common.GroupListInfo;
import com.un.ebs.core.common.KeyValueDto;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.OSSUtil;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.memorial.domain.*;
import com.un.ebs.memorial.dto.MemorialAddDto;
import com.un.ebs.memorial.dto.MemorialUpdateDto;
import com.un.ebs.memorial.dto.MemorialVo;
import com.un.ebs.memorial.enums.MemberTypeEnum;
import com.un.ebs.memorial.enums.MemorialRecordTypeEnum;
import com.un.ebs.memorial.mapper.*;
import com.un.ebs.memorial.service.MemorialResourceService;
import com.un.ebs.memorial.service.MemorialService;
import com.un.ebs.sys.domain.User;
import com.un.ebs.sys.domain.UserExt;
import com.un.ebs.sys.domain.UserWx;
import com.un.ebs.sys.service.RedisService;
import com.un.ebs.sys.service.UserService;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2020-03-12
 */
@Service
public class MemorialServiceImpl extends ServiceImpl<MemorialMapper, Memorial> implements MemorialService {

    private final String recordType_create = "6A8258BB-5B84-42F4-827D-AAD1916851FF";

    private final String memorial_logo = "memorial/logo";

    private final String memorial_resource_path = "memorial";
    private final String file_type_by_front_cover = "front_cover";
    private final String file_type_by_member_logo = "member_logo";
    private final String file_type_by_photo = "photo";

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private UserService userService;

    @Autowired
    private MemorialRecordExtMapper memorialRecordExtMapper;

    @Autowired
    private MemorialResourceService memorialResourceService;

    @Autowired
    private MemorialExtMapper memorialExtMapper;

    @Autowired
    private MemorialRecordTypeMapper memorialRecordTypeMapper;

    @Autowired
    private MemorialMemberExtMapper memorialMemberExtMapper;

    @Autowired
    private MemorialMemberMapper memorialMemberMapper;

    @Autowired
    private MemorialRecordMapper memorialRecordMapper;

    @Autowired
    private MemorialRecordTypeExtMapper memorialRecordTypeExtMapper;

    @Autowired
    private MemorialRecordPraiseMapper memorialRecordPraiseMapper;

    @Autowired
    private RedisService redisService;

    private String genResourcePath(String id, String type) {
        return String.format("%s/%s/%s", memorial_resource_path, id, type);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String add(MemorialAddDto req) {

        User user = null;
        UserWx userWx = userService.queryUserWx(req.getTenantId(), req.getOpenId());
        if (userWx == null) {
            user = userService.addByWx(req.getName(), req.getOpenId(), req.getOpenId(), req.getTenantId());
        } else {
            user = userService.getById(userWx.getUserId());
        }

        Memorial obj = new Memorial();
        obj.setName(req.getName());
        obj.setNameDesc(req.getNameDesc());
        obj.setCurrOpenId(req.getOpenId());
        obj.setContent(req.getContent());

        MemorialResource resourceImg = memorialResourceService.queryById(req.getBgImageId());
        if (resourceImg == null) {
            throw new BusinessException("指定的背景图片资源无效。");
        }
        obj.setCurrImage(resourceImg.getId());

        MemorialResource resourceMusic = memorialResourceService.queryById(req.getBgMusicId());
        if (resourceMusic == null) {
            throw new BusinessException("指定的背景音乐资源无效。");
        }

        if (redisService.get(req.getOpenId()) == null) {
            logger.error("创建纪念馆时，openId 缓存为空。");
            return null;
        }
        WxMpUser wxMpUser = redisService.get(req.getOpenId());
        if (StringUtils.isNullOrEmpty(wxMpUser.getHeadImgUrl())) {
            logger.error("创建纪念馆时，微信头像没有找到。");
        }
        String urlKey = OSSUtil.upload(wxMpUser.getHeadImgUrl(), genResourcePath(obj.getId(), file_type_by_member_logo), ".jpg");
        obj.setCurrMusic(resourceMusic.getId());
        obj.setIsDelete(false);
        obj.setCreateAt(user.getId());
        obj.setCreateAtName(wxMpUser.getNickname());
        obj.setLogo(urlKey);
        obj.insert();

        MemorialMember objMem = new MemorialMember();
        objMem.setCreateAt(user.getId());
        objMem.setMemorialId(obj.getId());
        objMem.setName(wxMpUser.getNickname());
        objMem.setCreateAtLogo(urlKey);
        objMem.setMemberType(MemberTypeEnum.Admin);
        objMem.insert();

        MemorialRecord objRecord = new MemorialRecord();
        objRecord.setCreateAt(user.getId());
        objRecord.setMemorialId(obj.getId());
        objRecord.setMemberId(objMem.getId());
        objRecord.setRecordTypeId(recordType_create);
        objRecord.insert();

        return obj.getId();
    }

    private String addMember(String memorialId, String userId) {
        UserExt user = userService.getUserExt(userId);
        if (user == null) {
            throw new BusinessException("您当前没有注册。");
        }
        LambdaQueryWrapper<MemorialMember> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialMember::getCreateAt, userId);
        lq.eq(MemorialMember::getMemorialId, memorialId);
        List<MemorialMember> list = memorialMemberMapper.selectList(lq);
        WxMpUser wxMpUser = redisService.get(user.getOpenId());
        MemorialMember obj = null;
        if (list.stream().findFirst().isPresent()) {
            obj = list.stream().findFirst().get();
        } else {
            obj = new MemorialMember();
            obj.setCreateAt(userId);
            obj.setMemorialId(memorialId);
            obj.setMemberType(MemberTypeEnum.Other);
            obj.setLastUpdateTime(new Date());

            if (StringUtils.isNullOrEmpty(user.getPersonnelName())) {
                obj.setName(wxMpUser.getNickname());
            } else {
                obj.setName(user.getPersonnelName());
            }
            obj.insert();
        }
        if (StringUtils.isNullOrEmpty(obj.getCreateAtLogo())) {
            obj.setCreateAtLogo(OSSUtil.upload(wxMpUser.getHeadImgUrl(), genResourcePath(obj.getId(), file_type_by_member_logo), ".jpg"));
        }
        obj.insertOrUpdate();
        return obj.getId();
    }

    @Override
    public void update(MemorialUpdateDto req) {
        Memorial obj = getById(req.getId());
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", req.getId()));
            return;
        }
        obj.setName(req.getName());
        obj.setNameDesc(req.getNameDesc());
        obj.setContent(req.getContent());
        obj.setLogo(req.getLogo());
        obj.setCurrImage(req.getCurrImage());
        obj.setCurrMusic(req.getCurrMusic());
        obj.updateById();
    }

    @Override
    public void delete(String id) {
        getBaseMapper().deleteById(id);
    }

    @Override
    public void updateName(String id, String name) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        obj.setName(name);
        obj.updateById();
    }

    @Override
    public void updateNameDesc(String id, String nameDesc) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        obj.setNameDesc(nameDesc);
        obj.updateById();
    }

    @Override
    public void updateContent(String id, String content) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        obj.setContent(content);
        obj.updateById();
    }

    @Override
    public void updateLogo(String id, MultipartFile file) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        String url = OSSUtil.upload(file, genResourcePath(id, file_type_by_member_logo));
        obj.setLogo(url);
        obj.updateById();
    }

    @Override
    public void updatePhoto(String id, List<MultipartFile> files) {
        OSSUtil.batchUpload(files, genResourcePath(id, file_type_by_photo));
    }

    @Override
    public void removePhoto(String key) {
        OSSUtil.delete(key);
    }

    @Override
    public List<KeyValueDto> queryPhotos(String id) {
        List<String> ids = OSSUtil.listKey(genResourcePath(id, file_type_by_photo));
        List<KeyValueDto> result = new ArrayList<>();
        for (String key : ids) {
            result.add(new KeyValueDto(key, OSSUtil.getObjectUrl(key).toString()));
        }
        return result;
    }

    @Override
    public void updateFrontCover(String id, MultipartFile file) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        String url = OSSUtil.upload(file, genResourcePath(id, file_type_by_front_cover));
        obj.setFrontCover(url);
        obj.updateById();
    }

    @Override
    public void updateImage(String id, String image) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        obj.setCurrImage(image);
        obj.updateById();
    }

    @Override
    public void updateMusic(String id, String music) {
        Memorial obj = queryById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            return;
        }
        obj.setCurrMusic(music);
        obj.updateById();
    }

    @Override
    public void record(String memorialId, String typeId, String remark) {
        MemorialRecord obj = new MemorialRecord();
        obj.setMemorialId(memorialId);
        obj.setRecordTypeId(typeId);
        obj.setRemark(remark);
        obj.setCreateAt(SecurityUtils.getUserContent().getId());
        obj.setMemberId(addMember(memorialId, SecurityUtils.getUserContent().getId()));
        obj.insert();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int commentPraise(String recordId) {
        LambdaQueryWrapper<MemorialRecordPraise> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialRecordPraise::getRecordId, recordId);
        lq.eq(MemorialRecordPraise::getUserId, SecurityUtils.getUserContent().getId());
        MemorialRecordPraise objRec = memorialRecordPraiseMapper.selectOne(lq);
        if (objRec == null) {
            MemorialRecord obj = memorialRecordMapper.selectById(recordId);
            if (obj != null) {
                obj.setPraiseCount(obj.getPraiseCount() + 1);
                obj.updateById();

                MemorialRecordPraise priase = new MemorialRecordPraise();
                priase.setRecordId(recordId);
                priase.setUserId(SecurityUtils.getUserContent().getId());
                priase.insert();
            }
            return obj.getPraiseCount();
        }
        return 0;
    }

    private String getDefaultCommentType(String id) {
        LambdaQueryWrapper<MemorialRecordTypeExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialRecordTypeExt::getType, MemorialRecordTypeEnum.Comment);
        lq.eq(MemorialRecordTypeExt::getMemorialId, id);
        Optional<MemorialRecordTypeExt> obj = memorialRecordTypeExtMapper.selectList(lq).stream().findFirst();
        if (obj.isPresent()) {
            return obj.get().getId();
        } else {
            throw new BusinessException("没有查到留言的typeId");
        }
    }

    @Override
    public void recordComment(String memorialId, String content) {
        record(memorialId, getDefaultCommentType(memorialId), content);
    }

    @Override
    public List<Memorial> queryByUserId(String userId) {
        LambdaQueryWrapper<Memorial> lq = Wrappers.lambdaQuery();
        lq.eq(Memorial::getCreateAt, userId);
        lq.eq(Memorial::getIsDelete, false);
        lq.orderByDesc(Memorial::getCreateTime);
        return baseMapper.selectList(lq);
    }

    @Override
    public List<MemorialExt> queryViewByDefunctId(String id) {
        LambdaQueryWrapper<MemorialExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialExt::getDefunctId, id);
        lq.eq(MemorialExt::getIsDelete, false);
        return memorialExtMapper.selectList(lq);
    }

    @Override
    public Memorial queryById(String id) {
        return getBaseMapper().selectById(id);
    }

    @Override
    public MemorialExt queryExtById(String id) {
        return memorialExtMapper.selectById(id);
    }

    private String getResourceUrl(String id) {
        return getResourceUrl(id, null);
    }

    private String getResourceUrl(String id, String style) {
        MemorialResource obj = memorialResourceService.queryById(id);
        if (obj != null) {
            if (StringUtils.isNullOrEmpty(style)) {
                return OSSUtil.getObjectUrl(obj.getUrl()).toString();
            } else {
                return OSSUtil.getObjectUrl(obj.getUrl(), style).toString();
            }
        }
        return null;
    }

    @Override
    public MemorialVo queryViewById(String id) {
        MemorialExt obj = queryExtById(id);
        if (obj == null) {
            logger.error(String.format("Memorial %s 没有找到。", id));
            throw new BusinessEntityNotFoundException(id, "memorial");
        }
        MemorialVo result = new MemorialVo();
        BeanUtils.copyProperties(obj, result);

        result.setCurrImageUrl(getResourceUrl(obj.getCurrImage()));
        result.setCurrMusicUrl(getResourceUrl(obj.getCurrMusic()));
        if (!StringUtils.isNullOrEmpty(result.getLogo())) {
            if (!result.getLogo().contains("http")) {
                result.setLogo(OSSUtil.getObjectUrl(result.getLogo()).toString());
            }
        }

        result.setMembers(queryMember(id));
        result.setRecordTypes(queryRecordTypeCount(id, null));

        return result;
    }

    @Override
    public IPage<MemorialExt> query(String name, int pageIndex, int pageSize) {
        return query(name, null, false, pageIndex, pageSize);
    }

    public IPage<MemorialExt> query(String name, String userId, Boolean isTop, int pageIndex, int pageSize) {
        Page<MemorialExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<MemorialExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialExt::getIsDelete, false);
        if (!StringUtils.isNullOrEmpty(userId)) {
            lq.eq(MemorialExt::getCreateAt, userId);
        }
        if (!StringUtils.isNullOrEmpty(name)) {
            lq.like(MemorialExt::getName, name);
            lq.or().like(MemorialExt::getCreateAtName, name);
        }
        if (!(isTop == null)) {
            lq.eq(MemorialExt::getIsTop, isTop);
        }
        lq.orderByDesc(MemorialExt::getMemberCount);
        IPage<MemorialExt> result = memorialExtMapper.selectPage(page, lq);
        for (int i = 0; i < result.getRecords().size(); i++) {
            if (!StringUtils.isNullOrEmpty(result.getRecords().get(i).getLogo())) {
                //过滤掉有效的URL
                if (!result.getRecords().get(i).getLogo().contains("http")) {
                    result.getRecords().get(i).setLogo(OSSUtil.getObjectUrl(result.getRecords().get(i).getLogo()).toString());
                }
            }
            if (StringUtils.isNullOrEmpty(result.getRecords().get(i).getFrontCover())) {
                result.getRecords().get(i).setCurrImageUrl(getResourceUrl(result.getRecords().get(i).getCurrImage(), "memorial_list_bg"));
            } else {
                result.getRecords().get(i).setCurrImageUrl(OSSUtil.getObjectUrl(result.getRecords().get(i).getFrontCover()).toString());
                result.getRecords().get(i).setFrontCover(OSSUtil.getObjectUrl(result.getRecords().get(i).getFrontCover()).toString());
            }
            result.getRecords().get(i).setCurrMusicUrl(getResourceUrl(result.getRecords().get(i).getCurrMusic()));
        }
        return result;
    }

    @Override
    public List<GroupListInfo<MemorialExt>> queryHomePage(int pageSize) {
        List<GroupListInfo<MemorialExt>> result = new ArrayList<>();

        GroupListInfo<MemorialExt> g1 = new GroupListInfo<>();
        g1.setName("公益纪念");
        g1.setId("1");
        g1.setTag("top");
        g1.setItems(query(null, null, true, 1, 999).getRecords());
        result.add(g1);

        GroupListInfo<MemorialExt> g2 = new GroupListInfo<>();
        g2.setName("热点");
        g2.setId("2");
        g2.setTag("hot");
        g2.setItems(query(null, null, false, 1, pageSize).getRecords());
        result.add(g2);

        GroupListInfo<MemorialExt> g3 = new GroupListInfo<>();
        g3.setName("我的");
        g3.setId("3");
        g3.setTag("myself");
        g3.setItems(query(null, SecurityUtils.getUserContent().getId(), null, 1, pageSize).getRecords());
        result.add(g3);

        return result;
    }

    @Override
    public List<MemorialMemberExt> queryMember(String id) {
        LambdaQueryWrapper<MemorialMemberExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialMemberExt::getMemorialId, id);
        lq.orderByDesc(MemorialMemberExt::getLastUpdateTime);
        List<MemorialMemberExt> list = memorialMemberExtMapper.selectList(lq);
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setCreateAtLogo(OSSUtil.getObjectUrl(list.get(i).getCreateAtLogo()).toString());
        }
        return list;
    }

    @Override
    public List<MemorialRecordTypeExt> queryRecordTypeCount(String id, String typeId) {
        List<MemorialRecordTypeEnum> types = new ArrayList<>();
        types.add(MemorialRecordTypeEnum.Photo);
        types.add(MemorialRecordTypeEnum.Comment);
        types.add(MemorialRecordTypeEnum.UIButton);

        LambdaQueryWrapper<MemorialRecordTypeExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialRecordTypeExt::getMemorialId, id);
        lq.in(MemorialRecordTypeExt::getType, types);
        if (!StringUtils.isNullOrEmpty(typeId)) {
            lq.eq(MemorialRecordTypeExt::getId, typeId);
        }
        lq.orderByAsc(MemorialRecordTypeExt::getSort);
        return memorialRecordTypeExtMapper.selectList(lq);
    }

    @Override
    public List<MemorialRecordType> queryRecordType() {
        LambdaQueryWrapper<MemorialRecordType> lq = Wrappers.lambdaQuery();
        lq.orderByAsc(MemorialRecordType::getSort);
        return memorialRecordTypeMapper.selectList(lq);
    }

    @Override
    public IPage<MemorialRecordExt> queryComment(String id, int pageIndex, int pageSize) {
        LambdaQueryWrapper<MemorialRecordType> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialRecordType::getType, MemorialRecordTypeEnum.Comment);
        List<String> typeIds = memorialRecordTypeMapper.selectList(lq).stream().map(s -> s.getId()).collect(Collectors.toList());

        return queryRecord(id, typeIds, pageIndex, pageSize);
    }

    public IPage<MemorialRecordExt> queryRecord(String id, List<String> typeIds, int pageIndex, int pageSize) {
        IPage<MemorialRecordExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<MemorialRecordExt> lq = Wrappers.lambdaQuery();
        lq.eq(MemorialRecordExt::getMemorialId, id);
        if (!StringUtils.isNullOrEmpty(typeIds)) {
            lq.in(MemorialRecordExt::getRecordTypeId, typeIds);
        }
        lq.orderByDesc(MemorialRecordExt::getCreateTime);
        IPage<MemorialRecordExt> result = memorialRecordExtMapper.selectPage(page, lq);

        List<String> ids = result.getRecords().stream().map(s -> s.getId()).collect(Collectors.toList());
        if (!StringUtils.isNullOrEmpty(ids)) {
            LambdaQueryWrapper<MemorialRecordPraise> queryCount = Wrappers.lambdaQuery();
            queryCount.in(MemorialRecordPraise::getRecordId, ids);
            queryCount.eq(MemorialRecordPraise::getUserId, SecurityUtils.getUserContent().getId());
            List<MemorialRecordPraise> recordPraises = memorialRecordPraiseMapper.selectList(queryCount);

            for (int i = 0; i < result.getRecords().size(); i++) {
                String recordId = result.getRecords().get(i).getId();
                long cnt = recordPraises.stream().filter(s -> s.getRecordId().equals(recordId)).count();
                result.getRecords().get(i).setIsPraise(cnt > 0);
            }
        }
        return result;
    }

    @Override
    public IPage<MemorialRecordExt> queryRecord(String id, String typeId, int pageIndex, int pageSize) {
        List<String> ids = new ArrayList<>();
        ids.add(typeId);
        return queryRecord(id, ids, pageIndex, pageSize);
    }
}